Skip to content

Add app validate command#6934

Queued
ryancbahan wants to merge 1 commit intomainfrom
rcb/non-interactive-validate
Queued

Add app validate command#6934
ryancbahan wants to merge 1 commit intomainfrom
rcb/non-interactive-validate

Conversation

@ryancbahan
Copy link
Contributor

@ryancbahan ryancbahan commented Mar 3, 2026

WHY are these changes introduced?

Adds a shopify app validate command that checks app configuration and extension TOMLs for errors without running a full dev or deploy. This gives developers (and agents) a fast, non-interactive way to verify config correctness.

WHAT is this pull request doing?

  • New command: app validate (packages/app/src/cli/commands/app/validate.ts)
    • Extends AppLinkedCommand so it links to the user's app via linkedAppContext() (same flow as deploy, dev, etc.)
    • Passes unsafeReportMode: true to collect all validation errors instead of failing on the first one
    • Renders a success message if config is valid, or a formatted error summary + AbortError if not
    • Supports standard app flags: --path, --config, --client-id, --reset
  • Service layer (packages/app/src/cli/services/validate.ts)
    • validateApp() reads app.errors, formats them, and renders success/error output
  • Registered in CLI — added to packages/app/src/cli/index.ts command map and oclif manifest

Demo

Screen Recording 2026-03-03 at 4.23.01 PM.mov (uploaded via Graphite)

How to test your changes?

  1. In an app directory with a valid shopify.app.toml, run shopify app validate — should see success message
  2. Introduce an error in the TOML (e.g. remove a required field) and run again — should see formatted validation errors and a non-zero exit code
  3. Test with --config flag pointing to a specific config file
  4. Run npx vitest run packages/app/src/cli/services/validate.test.ts — 3 tests covering valid, invalid, and empty-errors cases

Measuring impact

How do we know this change was effective? Please choose one:

  • n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes

Copy link
Contributor Author

ryancbahan commented Mar 3, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Coverage report

St.
Category Percentage Covered / Total
🟢 Statements 82.01% 14656/17870
🟡 Branches 74.38% 7263/9765
🟢 Functions 81.19% 3720/4582
🟢 Lines 82.42% 13858/16814

Test suite run success

3814 tests passing in 1475 suites.

Report generated by 🧪jest coverage report action from 4518b8f

@ryancbahan ryancbahan force-pushed the rcb/non-interactive-validate branch from f60cfc4 to 07ccc99 Compare March 11, 2026 16:47
@ryancbahan ryancbahan force-pushed the rcb/non-interactive-validate branch from 07ccc99 to 43d79a4 Compare March 18, 2026 15:37
@ryancbahan ryancbahan marked this pull request as ready for review March 18, 2026 15:39
@ryancbahan ryancbahan requested review from a team as code owners March 18, 2026 15:39
@ryancbahan ryancbahan changed the title add validate command Add app validate command Mar 18, 2026
@ryancbahan ryancbahan force-pushed the rcb/non-interactive-validate branch from 43d79a4 to 9b6498f Compare March 18, 2026 15:44
@github-actions
Copy link
Contributor

We detected some changes at packages/*/src and there are no updates in the .changeset.
If the changes are user-facing, run pnpm changeset add to track your changes and include them in the next release CHANGELOG.

Caution

DO NOT create changesets for features which you do not wish to be included in the public changelog of the next CLI release.

@ryancbahan ryancbahan force-pushed the rcb/non-interactive-validate branch 3 times, most recently from 16693ee to 56e26a3 Compare March 18, 2026 16:00
Copy link
Contributor

@dmerand dmerand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great. I found a few questions that should be answered prior to shipping.

export default class Validate extends AppLinkedCommand {
static summary = 'Validate your app configuration and extensions.'

static descriptionWithMarkdown = `Validates your app's \`shopify.app.toml\` and all extension configurations against their schemas and reports any errors found.`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Improvement: The help text currently says the command validates shopify.app.toml, but the implementation accepts --config and forwards that selected config name into app loading. Because this string also feeds generated help artifacts, reviewers may want the wording to match the broader behavior so docs, README output, and manifest metadata stay accurate.

Suggestion: Consider broadening the description so it reflects both default and explicit config-file selection:

Suggested change
static descriptionWithMarkdown = `Validates your app's \`shopify.app.toml\` and all extension configurations against their schemas and reports any errors found.`
static descriptionWithMarkdown = `Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.`

body: errorMessages.join('\n\n'),
})

throw new AbortError('App configuration is invalid.')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This service already renders the full validation report itself in [[file:packages/app/src/cli/services/validate.ts:16-19]], so throwing a normal AbortError afterward likely sends execution through the standard CLI fatal-error path as well. That would leave users with the detailed validation banner followed by a second generic failure banner, which is noisy and less informative.

There is already a matching pattern elsewhere in the app codebase for this case: when code manually renders its own error banner, it throws AbortSilentError instead of AbortError so the process still exits non-zero without duplicate output. See [[file:packages/app/src/cli/services/release/version-diff.ts:31-39]].

I think this should follow that same pattern here:

Suggested change
throw new AbortError('App configuration is invalid.')
throw new AbortSilentError()

The test should move with it too. [[file:packages/app/src/cli/services/validate.test.ts:27-33]] currently expects AbortError, which appears to lock in the wrong behavior rather than catching the duplicate-render case.

@github-actions
Copy link
Contributor

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/private/node/session/exchange.d.ts
@@ -6,20 +6,6 @@ export declare class InvalidGrantError extends ExtendableError {
 }
 export declare class InvalidRequestError extends ExtendableError {
 }
-export interface ExchangeScopes {
-    admin: string[];
-    partners: string[];
-    storefront: string[];
-    businessPlatform: string[];
-    appManagement: string[];
-}
-/**
- * Given an identity token, request an application token.
- * @param identityToken - access token obtained in a previous step
- * @param store - the store to use, only needed for admin API
- * @returns An array with the application access tokens.
- */
-export declare function exchangeAccessForApplicationTokens(identityToken: IdentityToken, scopes: ExchangeScopes, store?: string): Promise<Record<string, ApplicationToken>>;
 /**
  * Given an expired access token, refresh it to get a new one.
  */
packages/cli-kit/dist/private/node/session/schema.d.ts
@@ -12,8 +12,8 @@ declare const IdentityTokenSchema: zod.ZodObject<{
 }, "strip", zod.ZodTypeAny, {
     accessToken: string;
     refreshToken: string;
-    scopes: string[];
     expiresAt: Date;
+    scopes: string[];
     userId: string;
     alias?: string | undefined;
 }, {
@@ -34,8 +34,8 @@ declare const ApplicationTokenSchema: zod.ZodObject<{
     storeFqdn: zod.ZodOptional<zod.ZodString>;
 }, "strip", zod.ZodTypeAny, {
     accessToken: string;
-    scopes: string[];
     expiresAt: Date;
+    scopes: string[];
     storeFqdn?: string | undefined;
 }, {
     accessToken: string;
@@ -54,8 +54,8 @@ declare const SessionSchema: zod.ZodObject<{
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -73,8 +73,8 @@ declare const SessionSchema: zod.ZodObject<{
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -88,8 +88,8 @@ declare const SessionSchema: zod.ZodObject<{
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -103,8 +103,8 @@ declare const SessionSchema: zod.ZodObject<{
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -116,16 +116,16 @@ declare const SessionSchema: zod.ZodObject<{
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -166,8 +166,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -185,8 +185,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -200,8 +200,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -215,8 +215,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -228,16 +228,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -269,8 +269,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -288,8 +288,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -303,8 +303,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -318,8 +318,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -331,16 +331,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -372,8 +372,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -391,8 +391,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -406,8 +406,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -421,8 +421,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -434,16 +434,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -475,8 +475,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -494,8 +494,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -509,8 +509,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -524,8 +524,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -537,16 +537,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -578,8 +578,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -597,8 +597,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -612,8 +612,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -627,8 +627,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -640,16 +640,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -681,8 +681,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -700,8 +700,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -715,8 +715,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -730,8 +730,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -743,16 +743,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -784,8 +784,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -803,8 +803,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -818,8 +818,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -833,8 +833,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -846,16 +846,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -887,8 +887,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -906,8 +906,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -921,8 +921,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -936,8 +936,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -949,16 +949,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
@@ -990,8 +990,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     }, {
@@ -1009,8 +1009,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -1024,8 +1024,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -1039,8 +1039,8 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
         storeFqdn: zod.ZodOptional<zod.ZodString>;
     }, "strip", zod.ZodTypeAny, {
         accessToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         storeFqdn?: string | undefined;
     }, {
         accessToken: string;
@@ -1052,16 +1052,16 @@ export declare const SessionsSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{}
     identity: {
         accessToken: string;
         refreshToken: string;
-        scopes: string[];
         expiresAt: Date;
+        scopes: string[];
         userId: string;
         alias?: string | undefined;
     };
     applications: {} & {
         [k: string]: {
             accessToken: string;
-            scopes: string[];
             expiresAt: Date;
+            scopes: string[];
             storeFqdn?: string | undefined;
         };
     };
packages/cli-kit/dist/private/node/session/validate.d.ts
@@ -1,12 +1,11 @@
 import { Session } from './schema.js';
-import { OAuthApplications } from '../session.js';
 type ValidationResult = 'needs_refresh' | 'needs_full_auth' | 'ok';
 /**
- * Validate if the current session is valid or we need to refresh/re-authenticate
+ * Validate if the current session is valid or we need to refresh/re-authenticate.
+ * With PCAT, only the identity token needs validation - no per-application tokens.
  * @param scopes - requested scopes to validate
- * @param applications - requested applications
- * @param session - current session with identity and application tokens
+ * @param session - current session with identity token
  * @returns 'ok' if the session is valid, 'needs_full_auth' if we need to re-authenticate, 'needs_refresh' if we need to refresh the session
  */
-export declare function validateSession(scopes: string[], applications: OAuthApplications, session: Session | undefined): Promise<ValidationResult>;
+export declare function validateSession(scopes: string[], session: Session | undefined): Promise<ValidationResult>;
 export {};
\ No newline at end of file

@ryancbahan ryancbahan force-pushed the rcb/non-interactive-validate branch from 56e26a3 to 4518b8f Compare March 18, 2026 16:23
@ryancbahan ryancbahan requested a review from dmerand March 18, 2026 16:26
Copy link
Contributor

@dmerand dmerand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tophat LGTM, thanks for the changes!

Copy link
Contributor

@graygilmore graygilmore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only reviewed the files owned by us to remove our blocker.

@ryancbahan ryancbahan added this pull request to the merge queue Mar 18, 2026
Any commits made after this event will not be merged.
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 18, 2026
@ryancbahan ryancbahan added this pull request to the merge queue Mar 18, 2026
Any commits made after this event will not be merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants